-module(chat_svr).
-behaviour(gen_server).
-export([start/0,find/1]).

%% gen_server回调
-export([init/1,handle_call/3,handle_cast/2,handle_info/2, terminate/2,code_change/3]).
-compile(export_all).

-define(TCP_OPTIONS, [list, {packet, 0}, {active, false}, {reuseaddr, true},{nodelay, false},{delay_send, true}]).  
%%用户列表
-record(player, {id,socket,time=none}).


%%回调gen_server创建服务
start() ->
	gen_server:start_link({local,?MODULE},?MODULE,[8080],[]).%%定为8080端口

%%停止服务
stop()  ->
	gen_server:call(?MODULE,stop).

%%查找玩家
find(Uname)->
	client_manager ! {list,Uname}.


%%初始化,Port被持久化
init([Port]) ->
	%%维护队列
	register(client_manager, spawn(fun() -> manage_clients([]) end)),
	{Tag, LSocket}=gen_tcp:listen(Port, ?TCP_OPTIONS),
	case Tag of														%%创建监听
		ok		->	spawn(fun() -> do_accept(LSocket) end);			%%统一接收
		error	->	exit({accept, LSocket})                         %%出错，退出连接
	end,

    %%与flash通信的安全策略文件传送监听接口
    {Req, AsSocket}=gen_tcp:listen(843, ?TCP_OPTIONS),
    case Req of                                                               
        ok		-> spawn(fun() -> do_accept2(AsSocket) end);       
        error	-> exit({accept,AsSocket})                               
    end,
    {ok, LSocket}.


handle_call(stop,_From,Tab) ->
    client_manager!{exit},
    {stop,normal,stopped,Tab}.

handle_cast(_Msg,State) ->
	{noreply,State}.


handle_info(_Info,State) ->
	{noreply,State}.


terminate(_Reason,_State) ->
	ok.

%%热交换
code_change(_OldVsn,State,_) ->
	{ok,State}.








%% -----------------------------------
%% -------------私有函数--------------
%% -----------------------------------



%%新建连接,只有新连接时才调用
do_accept(LSocket) ->
        case gen_tcp:accept(LSocket) of
                {ok, Socket}->
                        %%创建进程处理响应
                        spawn(fun() -> handle_client(Socket) end),
                        %%创建新连接,持久化
                        client_manager ! {connect, Socket},
                        do_accept(LSocket);
                _->ok                                                       
        end.       



%%处理flash安全策略文件的发送服务
do_accept2(LSocket) ->
        case gen_tcp:accept(LSocket) of
                {ok, Socket}->
                        spawn(fun() -> put_file(Socket) end),
                        do_accept2(LSocket);
                _->error
        end.

%%短连接策略，连接完关闭
%%flash安全沙箱处理守候服务
put_file(Socket)->
          case gen_tcp:recv(Socket, 0) of
                {ok, _} ->
                        %%判断数据返回策略文件
                        gen_tcp:send(Socket, "<?xml version=\"1.0\"?>
                <cross-domain-policy>
                <allow-access-from domain=\"*\" to-ports=\"*\"/>  
                </cross-domain-policy>\0");
                {error, closed} ->ok
          end,
          gen_tcp:close(Socket).                                        %%关闭连接





%%持续、长连接的响应
handle_client(Socket) ->
          case gen_tcp:recv(Socket, 0) of
                {ok, Data} ->
                        client_manager ! {chat, Data},
                        handle_client(Socket);
                {error, closed} ->
                        client_manager ! {disconnect, Socket}                %%这里退出时会出错
          end.





%%对内响应,管理连接,事件列表,记录玩家数据
manage_clients(Players) ->
        receive
            {connect, Socket} ->
                Player = #player{
                        id="guest_"++integer_to_list(random:uniform(100000)),        %%随机命名用户名
                        socket=Socket,
                        time=time()
                        },        %%新增记录
                io:fwrite("Connected: ~w~n", [Socket]),
                NewPlayers =  [Player|Players];                                %%累加到列表

            {disconnect, Socket} ->
                io:fwrite("Disconnected: ~w~n", [Socket]),
                Player = find_Socket(Socket, Players),                        %%查找socket对应的记录
                NewPlayers = lists:delete(Player, Players);                %%删除记录

            {chat,Data} ->
                send_data(Players, Data),
                NewPlayers=Players;

            {list,Uname}->
                find_player(Uname,Players),
                NewPlayers = Players;

            {exit}->
                NewPlayers="",
                exit({exit})                                                %%退出系统应用
        end,
        manage_clients(NewPlayers).



%%对客户端进行广播
send_data(Players, Data) ->
  SendData = fun(Player) ->
    gen_tcp:send(Player#player.socket, Data)                                %%可设置为非阻断模式，或使用多进程发送
  end,
  lists:foreach(SendData, Players).

  %%查找指定记录
find_Socket(Socket, Players) ->
    {value, Player} = lists:keysearch(Socket, #player.socket, Players),
    Player.

find_player(Uname, Players) ->
    case lists:keysearch(Uname, #player.id, Players) of
    {value, Player}->
        io:fwrite("User information: ~w~n", [Player]);
    _->io:fwrite("No found.~n")
    end.